#![allow(dead_code)]
use mlua::{Function, Lua};
use tokio::macros::support::Future;
use prost::alloc::sync::Arc;
use super::ThreadTask;
use crate::taskpool::ThreadPool;
use std::pin::Pin;
use async_channel::{Sender,Receiver};


pub trait LoalLuaEval<Req,Res>{
    fn load(&self)-> Pin<Box<dyn Future<Output=(&'static Lua,Function<'static>)>>>;
    fn handle(&self,lua:&'static Lua,f:Function<'static>,req:Req)-> Pin<Box<dyn Future<Output=Res>>>;
}

pub enum LuaTask<Req,Res>{
    Async(Req),
    Await(Req,Sender<Res>)
}

#[derive(Clone)]
pub struct LuaPool<Req,Res>{
    pub sender : Arc<Sender<LuaTask<Req,Res>>>,
    pub receiver : Arc<Receiver<LuaTask<Req,Res>>>,
    load_eval:Arc<dyn LoalLuaEval<Req,Res> + Send + Sync + 'static>
}

impl<Req,Res:'static> LuaPool<Req,Res>{
    pub fn new<T:LoalLuaEval<Req,Res> + Send + Sync + 'static>(load:T) ->Self{
        let (sender,receiver) = async_channel::bounded::<LuaTask<Req,Res>>(1024);
        let sender = Arc::new(sender);
        let receiver = Arc::new(receiver);
        let load_eval = Arc::new(load);
        Self{sender,receiver,load_eval}
    }
    pub async fn spawn(&self, request:Req) -> Result<(), String> {
        let msg = LuaTask::Async(request);
        let res = self.sender.send(msg).await;
        match res {
            Ok(_)=>Ok(()),
            Err(e)=>Err(e.to_string())
        }
    }
    pub async fn block(&self, request:Req) -> Result<Res, String> {
        let (sender,receiver) = async_channel::unbounded::<Res>();
        let msg = LuaTask::Await(request,sender);
        if let Err(e) = self.sender.send(msg).await {
            return Err(e.to_string());
        }
        match receiver.recv().await {
            Ok(o)=>Ok(o),
            Err(e)=>Err(e.to_string())
        }
    }
    async fn async_call(_tp:ThreadPool,eval:Arc<dyn LoalLuaEval<Req,Res> + Send + Sync + 'static>,receiver:Arc<Receiver<LuaTask<Req,Res>>>){
        let (lua,handle) = eval.load().await;
        while !receiver.is_closed() {
            match receiver.recv().await {
                Ok(o)=>{
                    let eval_function = handle.clone();
                    match o {
                        LuaTask::Await(r,s)=>{
                            let async_handle = eval.handle(lua,eval_function,r);
                            tokio::task::spawn_local(async move{
                                let response = async_handle.await;
                                let _ = s.send(response).await;
                            });
                        }
                        LuaTask::Async(r)=>{
                            let async_handle = eval.handle(lua,eval_function,r);
                            tokio::task::spawn_local(async move{
                                let _ = async_handle.await;
                            });
                        }
                    };
                }
                Err(e)=>{
                    wd_log::log_error_ln!("接受任务错误：{}",e.to_string());
                }
            }
        }
        //销毁lua
        unsafe { Lua::from_static(lua) };
    }
}

impl<Req:'static,Res:'static> ThreadTask for LuaPool<Req,Res>{
    fn call(&self, tp: &ThreadPool) {
        let handle = self.load_eval.clone();
        let tp = tp.clone();
        let receiver = self.receiver.clone();
        thread_async_handle!(LuaPool::async_call(tp,handle,receiver).await);
    }
}